home *** CD-ROM | disk | FTP | other *** search
/ Precision Software Appli…tions Silver Collection 1 / Precision Software Applications Silver Collection Volume One (PSM) (1993).iso / windows / games / xlmath21.arj / SOURCE.ZIP / XLUTIL.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  26KB  |  1,011 lines

  1. /*******************************************************************
  2.  
  3.   XLUTIL.C
  4.   ==========
  5.  
  6.  Author & Copyright:    
  7.              Roy Kari
  8.              Dept. of Chemistry
  9.             Laurentian University
  10.             Sudbury, Ont.
  11.             Canada        P3E 2C6
  12.             (705) 675-1151
  13.             Internet: "ROY@NICKEL.LAURENTIAN.CA"
  14.  
  15.   This module contains all of the memory management routines for
  16.   Standalone DLL's. Optionally, the memory management is done with the aid
  17.   of the SMARTHEAP memory manager (c) Applegate Software (206)868-8512.
  18.  
  19.   This module also contains pascal string routines and Excel reference
  20.   manipulation rotuines.
  21.   ***************************************************************** */
  22.  
  23. /* --------------------------< Include files >--------------------- */
  24. #define WIN31
  25. #define _MSC_VER 700
  26.  
  27. #include <windows.h>
  28. #include <xlcall.h>
  29.  
  30. #include <stdlib.h>
  31.  
  32. #include <framewrk.h>
  33.  
  34. /*----------------------------------------------------------------------*\
  35.     You can use both XLAUTO and XLUTIL as general purpose modules
  36.     to be included in all of your XLL's. A few modifications are required
  37.     but these are easily handles by logical conditionals such as those
  38.     shown below.
  39. \*----------------------------------------------------------------------*/
  40. #ifdef _XLMATH
  41. #include <xlmath.h>
  42. #endif
  43. #ifdef _XLMARK
  44. #include <xlmark.h>
  45. #endif
  46. #ifdef _XLQC
  47. #include <.\xlqc\xlqc.h>
  48. #endif
  49.  
  50.  
  51. #include "xlutil.h"
  52.  
  53.  
  54. /*----------------------------------------------------------------------*\
  55.  
  56.                         Memory Utilities
  57.  
  58.     When I began this project, "real" mode windows was still a reality.
  59.     This meant that memory use was a "real" problem. The only way to
  60.     get by the problem was to use a memory allocator such as SMARTHEAP.
  61.     Today, with Windows 3.1 and finally Microsoft C/C++ 7, one can
  62.     go back to the "old fashioned way" of allocating memory - using 
  63.     the large model compiler and malloc() and free(). SMARTHEAP still 
  64.     provides memory debugging techniques superior to standard C but not 
  65.     superior to C++.
  66.  
  67.     My problem is that I wrote this mess with "real" mode in mind and
  68.     compiled it with casts to near and far pointers. I can easily
  69.     change to use old fashioned memory allocations but I cannot easily
  70.     change to the large model. Hence, what follows is a hybrid. In your
  71.     own usage, I suggest thast you forget about near and far data pointers 
  72.     and let the comiler sort it out.
  73.  
  74. \*----------------------------------------------------------------------*/
  75.  
  76.  
  77. /********************************************************************
  78.  GetMem()
  79.  =============
  80.  This function allocates memory for temporary storage
  81.  ********************************************************************/
  82. LPVOID PASCAL GetMem(WORD wBytes)
  83. {
  84.     LPVOID lpPtr;
  85.  
  86.     lpPtr = (LPVOID)MemAllocPtr(gScratchPool, wBytes, TRUE);
  87.  
  88.     if (lpPtr == NULL)
  89.         ErrorHandler(XLU_NO_MEMORY);
  90.  
  91.     return (lpPtr);
  92.  
  93. }
  94. /********************************************************************
  95.  FreeMem()
  96.  =============
  97.  This function de-allocates memory previously allocated in GetMem()
  98.  ********************************************************************/
  99. void PASCAL FreeMem(LPVOID lpPtr)
  100. {
  101.     if ((MemFreePtr((LPVOID)lpPtr) == FALSE))
  102.         ErrorHandler(XLU_MEMORY_ERROR);
  103.  
  104.     lpPtr = NULL;
  105.  
  106. }
  107.  
  108. /* -------------------< MALLOC SUBSTITUTE >--------------------- */
  109.  
  110. #ifndef _USE_SMARTHEAP
  111.  
  112. /*
  113. **     Basically, the routines below are dummy routines with the        **
  114. **     exception of the memory allocation routines which simply        **
  115. **     allocate memory in the far heap. If you use standard C            **
  116. **    then you can change the calls to the Microsoft far                **
  117. **    heap allocators _fmalloc() to the standard malloc() etc. I         **
  118. **    didn't because I wanted to retain the ability to use the medium **
  119. **    model with far data pointers.                                    **
  120. */
  121.  
  122. LPVOID PASCAL MemAllocPtr(MEM_POOL pool, WORD wSize,
  123.     BOOL bZeroInit)
  124. {
  125.  
  126.     if (bZeroInit)
  127.         return (LPVOID)_fcalloc((size_t) wSize, sizeof(char));
  128.     else
  129.         return (LPVOID)_fmalloc((size_t)wSize);
  130. }
  131.  
  132. LPVOID PASCAL  MemReAllocPtr(LPVOID lpMem, WORD wSize,
  133.     BOOL bZeroInit)
  134. {
  135.     size_t sizeOld, sizeNew;
  136.     LPVOID lpNew;
  137.  
  138.     if (bZeroInit)
  139.     {
  140.         sizeOld = _fmsize(lpMem);
  141.         lpNew = (LPVOID)_frealloc(lpMem, (size_t)wSize);
  142.         sizeNew = _fmsize(lpNew);
  143.         if ( sizeNew > sizeOld )
  144.         {
  145.             _fmemset((LPVOID)((LPSTR)lpNew+sizeOld), 0, 
  146.                         (size_t)(sizeNew-sizeOld) );
  147.             return lpNew;
  148.         }
  149.     }
  150.     else
  151.         return (LPVOID)_frealloc(lpMem, (size_t)wSize);
  152. }
  153.  
  154. BOOL PASCAL  MemFreePtr(LPVOID lpPtr)
  155. {
  156.     _ffree(lpPtr);
  157.     return TRUE;
  158. }
  159.  
  160. //
  161. //    The following are SMARTHEAP specific routines which here
  162. //    are duplicated as dummy routines.
  163. //
  164. MEM_POOL PASCAL MemPoolInit(BOOL bShared)
  165. {
  166.     return ((MEM_POOL)NULL);
  167. }
  168. BOOL PASCAL MemPoolFree(MEM_POOL pool)
  169. {
  170.     _fheapmin();
  171.     return TRUE;
  172. }
  173. DWORD PASCAL MemPoolCount(MEM_POOL pool)
  174. {
  175.     return (DWORD)0;
  176. }
  177. BOOL PASCAL MemCheckPtr(MEM_POOL pool, LPVOID lpPtr)
  178. {
  179.     // Can't do much here except check to see that the ptr is
  180.     // a ptr to a valid XLOPER of type multi
  181.  
  182.     return TRUE;    // do nothing
  183. }
  184. BOOL PASCAL MemSetSafetyLevel(int Dum1, BOOL bFlag)
  185. {
  186.     return bFlag;
  187. }
  188. #endif    // USE_SMARTHEAP
  189.  
  190. /*----------------------------------------------------------------------*\
  191.  
  192.                             Array Utilities
  193.                             
  194.     All data is passed back to Excel in an XLOPER of type
  195.     xltypeMulti. When using custom functions, this data memory
  196.     is released when Excel calls back xlAutoFree(). When using
  197.     dialog boxes, the memory is released in the dialog box routine.
  198.     It is more convenient to define a xlMulti data structure
  199.     whose memory can be deallocated with a single pointer. The
  200.     function InitMulti() allocates and initializes this xlMulti
  201.     array.
  202.  
  203. \*----------------------------------------------------------------------*/
  204.  
  205. /********************************************************************
  206.  InitMulti()
  207.  =============
  208.  This function allocates the XL MULTI array in global memory &
  209.  inits the array.
  210.  ********************************************************************/
  211. LPMULTI PASCAL InitMulti(WORD wRows, WORD wCols, WORD xlType)
  212. {
  213.     WORD wSizeData = sizeof(XLOPER)*wRows*wCols;
  214.     WORD i;
  215.     LPMULTI lpMulti = NULL;
  216.  
  217.     // the array is allocated in one shot which means
  218.     // that it can be freed with one pointer. There is no
  219.     // need to free the array memory separately
  220.     lpMulti = (LPMULTI)MemAllocPtr(gReturnPool,
  221.                         sizeof(XLOPER)*(wRows*wCols+1), FALSE);
  222.     if (lpMulti)
  223.     {
  224.             // init Multi to call back to xlAutoFree()
  225.             lpMulti->Info.xltype = (xltypeMulti | xlbitDLLFree);
  226.             // set the array pointer
  227.             lpMulti->Info.val.array.lparray = (LPXLOPER)&lpMulti->Data[0];
  228.             // set the rows
  229.             lpMulti->Info.val.array.rows  = wRows;
  230.             // set the columns
  231.             lpMulti->Info.val.array.columns = wCols;
  232.             for (i = 0; i < wRows*wCols; i++)
  233.             {
  234.                 // each XLOPER is initialized to type xlType and zeroed
  235.                 // note that the memory will be freed with lpMulti.
  236.                 lpMulti->Data[i].xltype = xlType;
  237.                 lpMulti->Data[i].val.num = 0.0;
  238.             }
  239.     }
  240.     else
  241.     {
  242.         ErrorHandler(XLU_NO_MEMORY);
  243.         return NULL;
  244.     }
  245.     return (lpMulti);
  246. }
  247. //
  248. //    InitNum() - Init an XLOPER of type Num
  249. //
  250. LPXLOPER PASCAL InitNum(VOID)
  251. {
  252.     LPXLOPER lpxlNum = (LPXLOPER)MemAllocPtr(gReturnPool,
  253.                                     sizeof(XLOPER), TRUE);
  254.     if (lpxlNum)
  255.     {
  256.         lpxlNum->xltype = xltypeNum | xlbitDLLFree;
  257.         lpxlNum->val.num = 0;
  258.     }
  259.     else
  260.     {
  261.         ErrorHandler(XLU_NO_MEMORY);
  262.         return NULL;
  263.     }
  264.     return (lpxlNum);
  265. }
  266. LPXLOPER StripxlbitDLLFree(LPXLOPER lpX)
  267. {
  268.     lpX->xltype = lpX->xltype ^ xlbitDLLFree;
  269.     return (lpX);
  270. }
  271.  
  272.  
  273. /********************************************************************
  274.  InitPointers()
  275.  =============
  276.  This function allocates memory and calculates the pointers for a 2-D
  277.  array. 
  278.  ********************************************************************/
  279. LPLPREAL PASCAL InitPointers(LPREAL lpData,
  280.             WORD wRows, WORD wCols)
  281. {
  282.     WORD id;
  283.     LPLPREAL lplpPtrs;
  284.     WORD wBytes = sizeof(LPREAL)*wRows;
  285.  
  286.     if ((lplpPtrs= (LPLPREAL)GetMem(wBytes))  == NULL)
  287.     {
  288.         ErrorHandler(XLU_NO_MEMORY);
  289.         return NULL;
  290.     }
  291.     // init row pointers
  292.     for(id = 0; id < wRows; id++)
  293.     {
  294.            lplpPtrs[id] = lpData;
  295.         lpData += wCols;
  296.     }
  297.     return(lplpPtrs);
  298. }
  299.  
  300.  
  301. /* ---------------------------------------------------------------------
  302.     Utility allocate and free space for dynamic 2D arrays
  303.    --------------------------------------------------------------------- */
  304. LPLPVOID AllocateArray2D(int NumberOfRows, int NumberOfColumns,
  305.             size_t SizeOfElement, size_t SizeOfPointers)
  306. {
  307.     register int i;
  308.     LPSTR lpArray;
  309.     LPLPSTR lplpRow;
  310.     size_t SizeOfRow;
  311.  
  312.     /* allocate memory for data */
  313.  
  314.     lpArray = (LPSTR)GetMem(NumberOfRows*NumberOfColumns*SizeOfElement);
  315.     if (lpArray == NULL)
  316.         {
  317.         return NULL;
  318.         }
  319.     /* allocate memory for row pointers */
  320.     lplpRow = (LPLPSTR)GetMem(NumberOfRows * SizeOfPointers);
  321.     if( lplpRow == NULL)
  322.         {
  323.         FreeMem( lpArray);
  324.         return NULL;
  325.         }
  326.     /* initialize row pointers */
  327.     SizeOfRow = SizeOfElement * NumberOfColumns;
  328.     for(i = 0; i < NumberOfRows; i++)
  329.         {
  330.         lplpRow[i] = lpArray;
  331.         lpArray += SizeOfRow;
  332.         }
  333.     return (LPLPVOID)lplpRow;
  334. }
  335. void FreeArray2D(LPLPVOID lplpRow)
  336. {
  337.     FreeMem((LPVOID)*lplpRow);    /* free the data space */
  338.     FreeMem((LPVOID)lplpRow);    /* free the row pointers */
  339. }
  340.  
  341. /*----------------------------------------------------------------------*\
  342.  
  343.  
  344.                         Error Handling Utilities
  345.  
  346.  
  347. \*----------------------------------------------------------------------*/
  348.  
  349. /********************************************************************
  350.  ErrorHandler()
  351.  ================
  352.  This function is used to display an error message
  353.  ********************************************************************/
  354.  
  355. BOOL PASCAL ErrorHandler(XLM_ERROR nErrorCode)
  356. {
  357.  
  358.     if (LoadString(ghLibInst, nErrorCode, gszErrorBuf, MAX_ERROR_STRING) > 0)
  359.     {
  360.         gszErrorBuf[0] = (BYTE)lstrlen((LPSTR)gszErrorBuf);
  361.         Excel(xlcAlert, 0, 3, (LPXLOPER)TempStr((LPSTR)gszErrorBuf),
  362.             (LPXLOPER)TempNum(3), (LPXLOPER)gpxHelpRef);
  363.     }
  364.     return TRUE;
  365. }
  366. /****************************************************************************
  367.  
  368.     FUNCTION: OkMsgBox(PSTR, PSTR, ...)
  369.  
  370.     PURPOSE:  Put a Formatted MessageBox
  371.  
  372. ****************************************************************************/
  373.  
  374. void cdecl OkMsgBox(LPSTR lpFormat, ...)
  375. {
  376.     static char rgch[256];
  377.  
  378.     wvsprintf(rgch, lpFormat, (LPSTR)((&lpFormat)+1));
  379.     rgch[0] = (BYTE)lstrlen((LPSTR)rgch);
  380.     Excel(xlcAlert, 0, 3, (LPXLOPER)TempStr((LPSTR)rgch),
  381.             (LPXLOPER)TempNum(2), (LPXLOPER)gpxHelpRef);
  382.  
  383. }
  384. #ifdef DEBUG
  385.  
  386. //
  387. // debugPrinto() - debugPrintf an xloper; Incomplete
  388. //
  389.  
  390. int PASCAL debugPrinto(LPXLOPER px)
  391. {
  392.     static char rgch[256];
  393.     LPXLMREF pxl;
  394.     WORD xltype = px->xltype & 0x0FFF;
  395.  
  396.     debugPrintf(" xltype=%x",px->xltype);
  397.     switch (xltype)
  398.     {
  399.         case    xltypeStr:
  400.             MakePstr((LPSTR)rgch,(LPSTR)px->val.str);
  401.             debugPrintf(" Str=%s",(LPSTR)rgch);
  402.         break;
  403.  
  404.         case    xltypeSRef:
  405.             debugPrintf(" count=%d \nrwF=%d rwL=%d colF=%d colL=%d",
  406.                 px->val.sref.count,      px->val.sref.ref.rwFirst,
  407.                 px->val.sref.ref.rwLast, px->val.sref.ref.colFirst,
  408.                 px->val.sref.ref.colLast);
  409.         break;
  410.         case    xltypeRef:
  411.             pxl = px->val.mref.lpmref;
  412.             debugPrintf(" count=%d \nrwF=%d rwL=%d colF=%d colL=%d",
  413.                 pxl->count,      
  414.                 pxl->reftbl[0].rwFirst,  pxl->reftbl[0].rwLast, 
  415.                 pxl->reftbl[0].colFirst, pxl->reftbl[0].colLast);
  416.         break;
  417.         case    xltypeMulti:
  418.             debugPrintf(" xltypeMulti\nrows=%d cols=%d\n lparray=%x : %x",
  419.                 px->val.array.rows, px->val.array.columns, 
  420.                 HIWORD(px->val.array.lparray), LOWORD(px->val.array.lparray));
  421.         break;
  422.         default:
  423.         break;
  424.     }
  425.     return 1;
  426. }
  427. #endif
  428.  
  429. /*----------------------------------------------------------------------*\
  430.  
  431.                         Pascal String Utilities
  432.  
  433.     Excel works with Pascal type strings which have a byte count
  434.     as the first byte in the string. This leads to several complications
  435.     which can be more easily resolved with the following utility functions.
  436.     
  437. \*----------------------------------------------------------------------*/
  438.  
  439.  
  440. //
  441. //    InitPascalStrings()
  442. //    Byte count the strings & add count to string
  443. //
  444. VOID InitPascalStrings (LPSTR  *lpStr, UINT nRows, UINT nCols)
  445. {
  446.     UINT i, j, ij;
  447.  
  448.     ij=0;
  449.     for (i=0; i<nRows; i++)
  450.     {
  451.         for (j=0; j<nCols; j++)
  452.         {
  453.             lpStr[ij+j][0] = (BYTE) lstrlen(lpStr[ij+j]+1);
  454.         }
  455.         ij += nCols;
  456.     }
  457. }
  458. //
  459. // MakePstr() - copy a C string to a Pascal type
  460. //    return no. char copied
  461. //
  462. int PASCAL MakePstr(LPSTR lpPstr, LPSTR lpCstr)
  463. {
  464.     BYTE i;
  465.  
  466.     lpPstr[0] = (BYTE)lstrlen(lpCstr);
  467.  
  468.     for (i=0; i<(BYTE)lpPstr[0]; i++)
  469.         lpPstr[i+1] = lpCstr[i];
  470.     return ((int)(BYTE)(lpPstr[0]));
  471.  
  472. }
  473.  
  474. //
  475. //    pstrcpy() copy a Pascal type string to a C type string
  476. //    return no. char copied
  477. //
  478. int PASCAL MakeCstr(LPSTR lpCstr, LPSTR lpPstr)
  479. {
  480.     BYTE i;
  481.  
  482.     lpCstr[0]='\0';
  483.  
  484.     if ( (BYTE)lpPstr[0]<256 )
  485.     {
  486.         for (i = 0; i < (BYTE)lpPstr[0]; i++)
  487.             lpCstr[i]=lpPstr[i+1];
  488.         lpCstr[i]='\0';
  489.     }
  490.     return (int)((BYTE)lpPstr[0]);
  491. }
  492. //
  493. //    lstrcatszpz(lpszstr1, lpsppstr2 ) concatenates sp string to
  494. //    sz string leaving sz string
  495. //
  496. LPSTR PASCAL lstrcatszsp(LPSTR lpszStr, LPSTR lpspStr)
  497. {
  498.     BYTE to, from, nchar;
  499.  
  500.     to = (BYTE)lstrlen((LPSTR)lpszStr);
  501.     from = 1;
  502.     nchar = (BYTE)lpspStr[0];
  503.  
  504.     while (nchar > 0)
  505.     {
  506.         lpszStr[to++] = lpspStr[from++];
  507.         --nchar;
  508.     }
  509.     lpszStr[to] = '\0';
  510.     return (LPSTR) lpszStr;
  511. }
  512.  
  513. /*
  514. ** lpstricmp
  515. **
  516. ** Compare two pascal strings and check if they are equal,
  517. ** without sensitivity to case.
  518. **
  519. ** Parameters:
  520. **
  521. **      LPSTR s     First string
  522. **      LPSTR t     Second string
  523. **
  524. ** Returns:
  525. **
  526. **      int         0 if they are equal
  527. **                  Nonzero otherwise
  528. **
  529. ** Note:
  530. **
  531. **      Unlike the usual string functions, lpstricmp
  532. **      doesn't care about collating sequence.
  533. */
  534.  
  535. int PASCAL lpstricmp(LPSTR s, LPSTR t)
  536. {
  537.     int i;
  538.  
  539.     if (*s != *t)
  540.     {
  541.         return 1;
  542.     }
  543.  
  544.     for (i=1; i<=s[0]; i++)
  545.     {
  546.         if (tolower(s[i]) != tolower(t[i]))
  547.         {
  548.             return 1;
  549.         }
  550.     }
  551.  
  552.     return 0;
  553. }
  554.  
  555. #if 0
  556. //    This just duplicates the Excel Find() function. It
  557. //    isn't required but I just don't have the heart to delete
  558. //    it!
  559. void Find(LPXLOPER pxPos, LPXLOPER pxFindT, LPXLOPER pxFindIn)
  560. {
  561.     BYTE i, j;
  562.     BOOL bSuccess = FALSE;
  563.  
  564.     for (i=1; i<=(BYTE)pxFindIn->val.str[0]; i++)
  565.     {
  566.         if (pxFindT->val.str[1] == pxFindIn->val.str[i])
  567.         {
  568.             bSuccess = TRUE;
  569.             if ((BYTE)pxFindT->val.str[0] > 1)
  570.             {
  571.                 for (j=0; j<(BYTE)pxFindT->val.str[0]; j++)
  572.                 {
  573.                     if (pxFindT->val.str[j+1] != pxFindIn->val.str[i+j])
  574.                     {
  575.                         bSuccess = FALSE;
  576.                         break;
  577.                     }
  578.                 }
  579.             }
  580.             break;
  581.         }
  582.  
  583.     }
  584.     if (bSuccess)
  585.     {
  586.         pxPos->xltype = xltypeNum;
  587.         pxPos->val.num = i;
  588.     }
  589.     else
  590.     {
  591.         pxPos->xltype = xltypeErr;
  592.         pxPos->val.err = 15;
  593.     }
  594. }
  595.  
  596. #endif
  597.  
  598. /*----------------------------------------------------------------------*\
  599.  
  600.                         Reference Utilities
  601.                         
  602.     The following group of routines will help you to retrieve
  603.     and create Excel ranges. This requires several helper routines
  604.     but with these rotuines, it is quite simple to retrieve ranges
  605.     from dialog boxes and create ranges to use with the xlSet command.
  606.     For usage, see the routines in XLMDLG.C    
  607.     
  608. \*----------------------------------------------------------------------*/
  609.  
  610. //////////////////////////////////////////////////////////////
  611. //
  612. //    InitDialog()
  613. //
  614. /////////////////////////////////////////////////////////////
  615. BOOL InitDialog(LPXLOPER lpxDialog, LPSTR *rgDlg, UINT nRows)
  616. {
  617.     LPXLOPER px;
  618.     UINT i, j, ij;
  619.  
  620.     px = lpxDialog->val.array.lparray = (LPXLOPER)GetMem(
  621.                                             (sizeof(XLOPER)*7*nRows));
  622.     if (px == NULL)
  623.         return FALSE;
  624.     // fill in the array
  625.     ij=0;
  626.     for (i=0; i<nRows; i++)
  627.     {
  628.         for (j=0; j<7; j++)
  629.         {
  630.             if (rgDlg[ij+j][0] == (BYTE)0)
  631.             {
  632.                 px->xltype = xltypeNil;
  633.             }
  634.             else
  635.             {
  636.                 px->xltype = xltypeStr;
  637.                 px->val.str = rgDlg[ij+j];
  638.             }
  639.             px++;
  640.         }
  641.         ij += 7;
  642.     }
  643.  
  644.     lpxDialog->xltype = xltypeMulti;
  645.     lpxDialog->val.array.rows = nRows;
  646.     lpxDialog->val.array.columns = 7;
  647.     return TRUE;
  648. }
  649.  
  650. //
  651. //    GetSheetId() - gets sheet name and sheetid for active sheet
  652. //    returns TRUE if found, else FALSE
  653. //
  654. BOOL GetActiveSheetId(void)
  655. {
  656.     BYTE i = 1;
  657.  
  658.     if (xlretSuccess != Excel(xlSheetId, &gxActiveSheetId, 0))
  659.     {
  660.         // error; no active sheet
  661.         ErrorHandler(XLU_NO_ACTIVESHEET);
  662.         return FALSE;
  663.     }
  664.  
  665.     // get active sheet's name
  666.     Excel(xlfGetWindow, &gxActiveSheetName, 1, TempInt(1));
  667.  
  668.     if (gxActiveSheetName.xltype == xltypeStr)
  669.     {
  670.         // save name in C string & get SheetId
  671.         MakeCstr((LPSTR)gszActiveSheetName, (LPSTR)gxActiveSheetName.val.str);
  672.         Excel(xlSheetId, (LPXLOPER)&gxActiveSheetId, 1,
  673.             (LPXLOPER)&gxActiveSheetName);
  674.         return TRUE;
  675.     }
  676.     // only in case of error
  677.     return FALSE;
  678.  
  679. }
  680.  
  681. //
  682. //    TrimPrefix() - strip the sheet name from a text reference
  683. //    if the text reference refers to the active sheet. Else
  684. //     does not strip sheetname
  685. //
  686. void PASCAL TrimPrefix(LPXLOPER pxRefText)
  687. {
  688.     BYTE i,j, len;
  689.     XLOPER xTemp;
  690.     XLOPER xSheetName1, xActiveSheetName;
  691.  
  692.     // get active sheet's name
  693.     Excel(xlfGetWindow, &xActiveSheetName, 1, TempInt(1));
  694.  
  695.     // extract sheet name from input ref
  696.  
  697.     Excel(xlfFind, &xTemp, 2, (LPXLOPER)TempStr((LPSTR)" !"), (LPXLOPER)pxRefText);
  698.  
  699. //    Find(&xTemp, TempStr((LPSTR)" !"), pxRefText);
  700.     if (xTemp.xltype != xltypeErr)
  701.     {
  702.         --xTemp.val.num;
  703.         Excel(xlfLeft, &xSheetName1, 2, (LPXLOPER)pxRefText,
  704.                 (LPXLOPER)&xTemp);
  705.         if (lpstricmp(xActiveSheetName.val.str, xSheetName1.val.str)==0)
  706.         {
  707.             // active and ref sheet names are the same
  708.             // strip sheet name from reference
  709.             j = (BYTE)xTemp.val.num + 1;
  710.             len = (BYTE)pxRefText->val.str[0] - j;
  711.             for (i=1; i<=len; i++)
  712.             {
  713.                 pxRefText->val.str[i] = pxRefText->val.str[i+j];
  714.             }
  715.             pxRefText->val.str[0] = len;
  716.         }
  717.     }
  718.  
  719.     Excel(xlFree, 0, 1, (LPXLOPER)&xSheetName1);
  720.     Excel(xlFree, 0, 1, (LPXLOPER)&xActiveSheetName);
  721.  
  722. }
  723. /////////////////////////////////////////////////////////////////////////////
  724. //
  725. //    GetRefTextFromSelection() - Initialize the dialog box reference edit 
  726. //    controls for both input and output. The input range is defined from 
  727. //    the selection and the output range is defined as to the right or below
  728. //
  729. ///////////////////////////////////////////////////////////////////////////
  730. int PASCAL GetRefTextFromSelection(LPXLOPER pxRefTextIn,
  731.                             LPXLOPER pxRefTextOut, BYTE Offset)
  732. {
  733.     XLOPER xSel, xOutRef;
  734.  
  735.     // get selection in text form
  736.     Excel(xlfSelection, (LPXLOPER)&xSel, 0);
  737.     if (xSel.xltype != xltypeSRef)
  738.     {
  739.         ErrorHandler(XLU_BAD_REF);
  740.         return FALSE;
  741.     }
  742.  
  743.     // create output reference
  744.     xOutRef.xltype=xltypeSRef;
  745.     xOutRef.val.sref.count=1;
  746.     if ((xSel.val.sref.ref.rwLast - xSel.val.sref.ref.rwFirst) >
  747.         (WORD)(xSel.val.sref.ref.colLast- xSel.val.sref.ref.colFirst) )
  748.     {
  749.         // rows > cols so to right
  750.         xOutRef.val.sref.ref.rwFirst = xOutRef.val.sref.ref.rwLast =
  751.             xSel.val.sref.ref.rwFirst;
  752.         xOutRef.val.sref.ref.colFirst = xOutRef.val.sref.ref.colLast =
  753.             xSel.val.sref.ref.colLast+(WORD)Offset;
  754.  
  755.     }
  756.     else
  757.     {
  758.         // rows < cols so below
  759.         xOutRef.val.sref.ref.rwFirst = xOutRef.val.sref.ref.rwLast =
  760.             xSel.val.sref.ref.rwLast + Offset;
  761.         xOutRef.val.sref.ref.colFirst = xOutRef.val.sref.ref.colLast =
  762.             xSel.val.sref.ref.colFirst;
  763.     }
  764.  
  765.     // convert to string form: this returns a string so must
  766.     // be freed later
  767.     Excel(xlfReftext, pxRefTextIn, 2, (LPXLOPER)&xSel, TempBool(TRUE));
  768.     Excel(xlfReftext, pxRefTextOut,2, (LPXLOPER)&xOutRef, TempBool(TRUE));
  769.  
  770.     // strip the sheet ID from the reference
  771.     TrimPrefix(pxRefTextIn);
  772.     TrimPrefix(pxRefTextOut);
  773.  
  774.     // free the selection string
  775.     Excel(xlFree, 0, 1, (LPXLOPER)&xSel);
  776.     return 1;
  777. }
  778. //
  779. //    SetInitalRange() - Sets the dialog box default from selected cell or range
  780. //
  781. int    PASCAL SetInitialRange(LPXLOPER pxRefText, LPXLOPER pxDlg, WORD wDlgRow)
  782. {
  783.     LPXLOPER px;
  784.  
  785.     // put into dialog box
  786.     px = (LPXLOPER)(&pxDlg->val.array.lparray[wDlgRow*7+6]);
  787.     px->xltype=xltypeStr;
  788.     px->val.str=pxRefText->val.str;
  789.     return 1;
  790. }
  791.  
  792. ////////////////////////////////////////////////////////////////////////
  793. //
  794. //     Global reference creation functions
  795. //    The global reference gxOutRef and gxInRef are used for
  796. //    communication with the worksheet. The following routines are
  797. //    used to create these global refences either from single
  798. //    references or general references. Generally, you will
  799. //    create a global reference and then define the size of the range
  800. //    with RefSetRectangle().
  801. //
  802. ///////////////////////////////////////////////////////////////////////
  803.  
  804. //
  805. //    CreateGlobalRef() - create a global refence. pgxRef is a global
  806. //    reference: gxOutRef or gxInRef. The global reference
  807. //  is created either from a single reference (xltypeSref) or
  808. //  a general reference (xltypeRef). The global references are
  809. //  limited to a single continuous range.
  810. //
  811. BOOL PASCAL CreateGlobalRef(LPXLOPER pgxRef, LPXLOPER pxDialog, WORD wDlgRow)
  812. {
  813.     XLOPER xTemp;
  814.  
  815.     // get range from dialog & change to reference
  816.     Excel(xlfTextref, &xTemp, 2,
  817.             (LPXLOPER)&pxDialog->val.array.lparray[wDlgRow*7+6],
  818.             TempBool(FALSE));
  819.  
  820.     // abort discontinuous regions or bad ref
  821.     if (!RefIsContinuous(&xTemp))
  822.     {
  823.         // abort multi region refs
  824.         ErrorHandler(XLU_BAD_REF);
  825.         Excel(xlFree, 0, 1, (LPXLOPER)&xTemp);
  826.         return FALSE;
  827.     }
  828.  
  829.     // create global REF
  830.     if (xTemp.xltype == xltypeSRef)
  831.     {
  832.         // SRef type reference, change to Ref
  833.         InitGlobalRefFromSRef(pgxRef, &xTemp);
  834.     }
  835.     else if (xTemp.xltype == xltypeRef)
  836.     {
  837.         // Ref type ref
  838.         InitGlobalRefFromRef(pgxRef, (LPXLOPER)&xTemp);
  839.     }
  840.     return TRUE;
  841. }
  842.  
  843. //
  844. //     RefIsContinuous() - returns true if SRef or continuous
  845. //
  846. BOOL PASCAL RefIsContinuous(LPXLOPER pxRef)
  847. {
  848.     LPXLMREF lpxlm;
  849.  
  850.     if (pxRef->xltype == xltypeSRef)
  851.         // SRef always continuous
  852.         return TRUE;
  853.     if (pxRef->xltype == xltypeRef)
  854.     {
  855.         // check count of Ref
  856.         lpxlm = pxRef->val.mref.lpmref;
  857.         // ok if unity
  858.         if (lpxlm->count == 1)
  859.             return TRUE;
  860.         else
  861.             return FALSE;
  862.     }
  863.     // not a ref
  864.     return FALSE;
  865. }
  866. //
  867. //    IsReferencesOverlapped() - check overlapping ranges
  868. //
  869. BOOL IsReferencesOverlapped(LPXLOPER pxRef1, LPXLOPER pxRef2)
  870. {
  871.     LPXLMREF lpxlm1, lpxlm2;
  872.  
  873.     // not reference  types
  874.     if (pxRef1->xltype != xltypeRef || pxRef2->xltype != xltypeRef)
  875.         return FALSE;
  876.  
  877.     // different id's not overlapped
  878.     if (pxRef1->val.mref.idSheet != pxRef2->val.mref.idSheet)
  879.         return FALSE;
  880.  
  881.     // single ref only
  882.     lpxlm1 = pxRef1->val.mref.lpmref;
  883.     lpxlm2 = pxRef2->val.mref.lpmref;
  884.  
  885.     // not if
  886.     if ((lpxlm1->reftbl[0].rwFirst    > lpxlm2->reftbl[0].rwLast)     ||    // below
  887.         (lpxlm1->reftbl[0].rwLast    < lpxlm2->reftbl[0].rwFirst)    ||    // above
  888.         (lpxlm1->reftbl[0].colFirst    > lpxlm2->reftbl[0].colLast)    ||    // to right
  889.         (lpxlm1->reftbl[0].colLast    < lpxlm2->reftbl[0].colFirst))        // to left
  890.         return FALSE;
  891.  
  892.     ErrorHandler(XLU_OVERLAPPED_REF);
  893.     return TRUE;
  894. }
  895. //
  896. //    InitGlobalRefFromSref()
  897. //
  898. void InitGlobalRefFromSRef(LPXLOPER pgxRef, LPXLOPER pxSRef)
  899. {
  900.     LPXLMREF lpmRef;
  901.  
  902.     // get pointer to xlmref from global ref
  903.     lpmRef = pgxRef->val.mref.lpmref;
  904.  
  905.     // set xltype
  906.     pgxRef->xltype = xltypeRef;
  907.  
  908.     // set SheetId
  909.     pgxRef->val.mref.idSheet = gxActiveSheetId.val.mref.idSheet;
  910.  
  911.     // set count
  912.     lpmRef->count = 1;
  913.  
  914.     // set rows
  915.     lpmRef->reftbl[0].rwFirst    = pxSRef->val.sref.ref.rwFirst;
  916.     lpmRef->reftbl[0].rwLast     = pxSRef->val.sref.ref.rwLast;
  917.  
  918.     // set cols
  919.     lpmRef->reftbl[0].colFirst    = pxSRef->val.sref.ref.colFirst;
  920.     lpmRef->reftbl[0].colLast    = pxSRef->val.sref.ref.colLast;
  921. }
  922. //
  923. //    InitGloablRefFromRef()
  924. //
  925. void InitGlobalRefFromRef(LPXLOPER pgxRef, LPXLOPER pxRef)
  926. {
  927.     LPXLMREF lpgmRef, lpmRef;
  928.  
  929.     // get pointer to global mref
  930.     lpgmRef = pgxRef->val.mref.lpmref;
  931.  
  932.     // get pointer to source reference mref
  933.     lpmRef = pxRef->val.mref.lpmref;
  934.  
  935.     // set xltype
  936.     pgxRef->xltype = xltypeRef;
  937.  
  938.     // set SheetId
  939.     pgxRef->val.mref.idSheet = pxRef->val.mref.idSheet;
  940.  
  941.     // set count
  942.     lpgmRef->count = 1;
  943.  
  944.     // set rows
  945.     lpgmRef->reftbl[0].rwFirst    = lpmRef->reftbl[0].rwFirst;
  946.     lpgmRef->reftbl[0].rwLast     = lpmRef->reftbl[0].rwLast;
  947.  
  948.     // set cols
  949.     lpgmRef->reftbl[0].colFirst = lpmRef->reftbl[0].colFirst;
  950.     lpgmRef->reftbl[0].colLast    = lpmRef->reftbl[0].colLast;
  951.  
  952. }
  953.  
  954. ////////////////////////////////////////////////////////////////////////
  955. //
  956. //     general reference helper functions
  957. //
  958. ///////////////////////////////////////////////////////////////////////
  959.  
  960. //
  961. // IncxlmRefRow() - increments the row to point to one row
  962. // below the row as defined in input. The range rectangle is 
  963. // not changed. This is used to write successive blocks one
  964. // below the next.
  965.  
  966. void IncxlmRefRow(LPXLOPER pxRef)
  967. {
  968.     LPXLMREF pxlmRef;
  969.     WORD wRows;
  970.  
  971.     // make the reference point to the row below the last
  972.     // never change the rectangle
  973.  
  974.     pxlmRef = pxRef->val.mref.lpmref;
  975.     wRows = pxlmRef->reftbl[0].rwLast - pxlmRef->reftbl[0].rwFirst + 1;
  976.     pxlmRef->reftbl[0].rwFirst = pxlmRef->reftbl[0].rwLast+1;
  977.     pxlmRef->reftbl[0].rwLast += wRows;
  978. }
  979.  
  980. //
  981. // IncxlmRefCol() - increment column (see InxlmRefRow() above
  982. //
  983.  
  984. void IncxlmRefCol(LPXLOPER pxRef)
  985. {
  986.     LPXLMREF pxlmRef;
  987.     BYTE nCols;
  988.  
  989.     // increment first col 1 greater than last
  990.  
  991.     pxlmRef = pxRef->val.mref.lpmref;
  992.     nCols = pxlmRef->reftbl[0].colLast - pxlmRef->reftbl[0].colFirst + 1;
  993.     pxlmRef->reftbl[0].colFirst = pxlmRef->reftbl[0].colLast+1;
  994.     pxlmRef->reftbl[0].colLast += nCols;
  995. }
  996. //
  997. // RefSetRectangle() - create a rectangular reference from a previously
  998. //    initialized reference.
  999. //
  1000.  
  1001. void RefSetRectangle(LPXLOPER pxRef, WORD wRows, BYTE nCols)
  1002. {
  1003.     LPXLMREF pxlmRef;
  1004.  
  1005.     // make the reference a rectangle based on first
  1006.  
  1007.     pxlmRef = pxRef->val.mref.lpmref;
  1008.     pxlmRef->reftbl[0].rwLast = pxlmRef->reftbl[0].rwFirst + wRows -1;
  1009.     pxlmRef->reftbl[0].colLast = pxlmRef->reftbl[0].colFirst + nCols -1;
  1010. }
  1011.